From 5907ff694fc7402982261922b1b8693efcfa3c8f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Thu, 29 Nov 2018 08:09:02 +0100 Subject: [PATCH] gl renderer: Render non-trivial transforms to a texture This way we can e.g. render rotated clips, borders, etc. --- gsk/gl/gskglrenderer.c | 63 +++++++++++++++++++++++++++++++++- gsk/gl/gskglrenderops.c | 13 +++++++ gsk/gl/gskglrenderopsprivate.h | 1 + 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index a75f8b3823..c92b71b0f2 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -219,6 +219,31 @@ gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self) MAX (self->corner[2].height, self->corner[3].height)) * 2); } +static inline gboolean +node_supports_transform (GskRenderNode *node) +{ + /* Some nodes can't handle non-trivial transforms without being + * rendered to a texture (e.g. rotated clips, etc.). Some however + * work just fine, mostly because they already draw their child + * to a texture and just render the texture manipulated in some + * way, think opacity or color matrix. */ + const guint node_type = gsk_render_node_get_node_type (node); + + switch (node_type) + { + case GSK_COLOR_NODE: + case GSK_OPACITY_NODE: + case GSK_COLOR_MATRIX_NODE: + case GSK_TEXTURE_NODE: + return TRUE; + + default: + return FALSE; + } + return FALSE; +} + + static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self); static void add_offscreen_ops (GskGLRenderer *self, RenderOpBuilder *builder, @@ -736,7 +761,43 @@ render_transform_node (GskGLRenderer *self, graphene_matrix_multiply (&transform, builder->current_modelview, &transformed_mv); ops_push_modelview (builder, &transformed_mv); - gsk_gl_renderer_add_render_ops (self, child, builder); + if (ops_modelview_is_simple (builder) || + node_supports_transform (child)) + { + gsk_gl_renderer_add_render_ops (self, child, builder); + } + else + { + const float min_x = builder->dx + child->bounds.origin.x; + const float min_y = builder->dy + child->bounds.origin.y; + const float max_x = min_x + child->bounds.size.width; + const float max_y = min_y + child->bounds.size.height; + const GskQuadVertex vertex_data[GL_N_VERTICES] = { + { { min_x, min_y }, { 0, 1 }, }, + { { min_x, max_y }, { 0, 0 }, }, + { { max_x, min_y }, { 1, 1 }, }, + + { { max_x, max_y }, { 1, 0 }, }, + { { min_x, max_y }, { 0, 0 }, }, + { { max_x, min_y }, { 1, 1 }, }, + }; + int texture_id; + gboolean is_offscreen; + /* For non-trivial transforms, we draw everything on a texture and then + * draw the texture transformed. */ + /* TODO: We should compute a modelview containing only the "non-trivial" + * part (e.g. the rotation) and use that. We want to keep the scale + * for the texture. + */ + add_offscreen_ops (self, builder, + min_x, max_x, min_y, max_y, + child, + &texture_id, &is_offscreen, + FALSE, TRUE); + ops_set_texture (builder, texture_id); + ops_set_program (builder, &self->blit_program); + ops_draw (builder, vertex_data); + } ops_pop_modelview (builder); } diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index 1ac8f8866e..85026d8e63 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -116,6 +116,19 @@ ops_transform_bounds_modelview (const RenderOpBuilder *builder, graphene_rect_offset (dst, builder->dx, builder->dy); } +gboolean +ops_modelview_is_simple (const RenderOpBuilder *builder) +{ + const MatrixStackEntry *head; + + g_assert (builder->mv_stack != NULL); + g_assert (builder->mv_stack->len >= 1); + + head = &g_array_index (builder->mv_stack, MatrixStackEntry, builder->mv_stack->len - 1); + + return head->metadata.simple; +} + void ops_set_program (RenderOpBuilder *builder, const Program *program) diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index 7b0b1f824f..97ce3a28b1 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -263,6 +263,7 @@ void ops_finish (RenderOpBuilder *builder); void ops_push_modelview (RenderOpBuilder *builder, const graphene_matrix_t *mv); void ops_pop_modelview (RenderOpBuilder *builder); +gboolean ops_modelview_is_simple (const RenderOpBuilder *builder); float ops_get_scale (const RenderOpBuilder *builder); void ops_set_program (RenderOpBuilder *builder, -- 2.30.2